/**
 * Copyright (C) 2021 - 2031 O-Cubes Co., Ltd.
 */

/****************************************************************
 *  @file    dw_spi.h
 *  @brief   Designware spi controller driver header file
 *  @version v1.0
 *  @date    03. Apr. 2023
 *  @author  liuchao
 ****************************************************************/

#ifndef __DW_SPI_H__
#define __DW_SPI_H__

#include <stdint.h>
#include "dev_spi.h"
#include "irq.h"
#include "sfud.h"

#ifdef __cplusplus
extern "C" {
#endif

/**
 * if this header file is included,
 * will indicate that this designware spi device
 * is used
 */
#define DEVICE_USE_DESIGNWARE_SPI

#define CTRLR0_DFS_MASK                 GENMASK(3, 0)
#define CTRLR0_DFS_32_MASK              GENMASK(20, 16)

#define CTRLR0_SECONV_OFFSET            25
#define CTRLR0_DFS_32_OFFSET            16
#define CTRLR0_DFS_16_OFFSET            0


#define SSI_MAX_XFER_SIZE_32            32
#define SSI_MAX_XFER_SIZE_16            16

#define SPI_DFS_DEFAULT                 8               /*!< Default spi data frame size */
#define SPI_DUMMY_DEFAULT               (0xFF)          /*!< default dummy value for first open */
#define DW_SPI_RX_SAMPLEDLY             0

#define DW_XIP_RD_WAIT_CYCLES           (4)
#define DW_QSPI_WAIT_CYCLES             (8)
#define DW_QSPI_INST_L_0                (0)
#define DW_QSPI_INST_L_2                (2)
#define DW_QSPI_ADDR_L_6                (6)
#define DW_QSPI_ADDR_L_8                (8)

#define DW_SPI_IN_FREE                  (0)                                     /*!< Currently not in spi transfer */
#define DW_SPI_IN_XFER                  (DEV_IN_TX | DEV_IN_RX | DEV_IN_XFER)   /*!< Currently in spi transfer */
#define DW_SPI_IN_TX                    (DEV_IN_TX | DEV_IN_XFER)               /*!< Currently in spi tx */
#define DW_SPI_IN_RX                    (DEV_IN_RX | DEV_IN_XFER)               /*!< Currently in spi rx */

#define DW_SPI_GINT_DISABLED            (0)                                     /*!< designware interrupt disabled for control spi irq/fiq */
#define DW_SPI_GINT_ENABLE              (1 << 0)                                /*!< designware interrupt enabled for control spi irq/fiq */

#define DW_SPI_MASTER_SUPPORTED         (0x1)                                   /*!< Support Designware SPI Master Mode */
#define DW_SPI_SLAVE_SUPPORTED          (0x2)                                   /*!< Support Designware SPI Slave Mode */
/*!< Support Designware SPI Both Master and Slave Mode */
#define DW_SPI_BOTH_SUPPORTED           (DW_SPI_MASTER_SUPPORTED | DW_SPI_SLAVE_SUPPORTED)

#define DW_SPI_INVALID_INTNO            (DEV_INTNO_INVALID)

/** SPI frame format */
typedef enum spi_frame_format {
	SPI_FRF_STD            = 0,                    /*Standard SPI Frame Format */
	SPI_FRF_DUAL           = 1,                    /*Dual SPI Frame Format */
	SPI_FRF_QUAD           = 2,                    /*Quad SPI Frame Format */
	SPI_FRF_OCTAL          = 3,                    /*Octal SPI Frame Format */
} SPI_FRAME_FORMAT;

/** SPI transfer mode */
typedef enum spi_trans_mode {
	SPI_TRANS_TX_AND_RX    = 0,                    /*Transmit and Receive mode */
	SPI_TRANS_TX_ONLY      = 1,                    /*Transmit only mode */
	SPI_TRANS_RX_ONLY      = 2,                    /*Receive only mode */
	SPI_TRANS_EEPROM_READ  = 3,                    /*EEPROM read mode */
} SPI_TRANS_MODE;

/** SPI Instruction and address transfer type */
typedef enum spi_trans_type {
	SPI_TRANS_TYPE_0       = 0,                    /*Instruction and address send in standard spi mode */
	SPI_TRANS_TYPE_1       = 1,                    /*Instruction send in standard spi mode and address send in qspi mode */
	SPI_TRANS_TYPE_2       = 2,                    /*Both instruction and address send in qspi mode */
} SPI_TRANS_TYPE;

/**
 * detailed description of DesignWare SPI register information
 */
/**
 * \brief	DesignWare SPI register structure
 * \details	Detailed struct description of DesignWare SPI
 * 	block register information, implementation of dev_spi_info::spi_regs
 */
typedef volatile struct dw_spi_reg {
	/*!< Control Register */
	/*!< SPI Control Register 0  (0x0) */
	uint32_t CTRLR0;
	/*!< SPI Control Register 1  (0x4) */
	uint32_t CTRLR1;
	/*!< Enable Register */
	/*!< SPI Enable Register  (0x8) */
	uint32_t SSIENR;
	/*!< SPI Microwire Control Register  (0xC) */
	uint32_t MWCR;
	/*!< SPI Slave Enable Register  (0x10) */
	uint32_t SER;
	/*!< SPI Baud Rate Select Register  (0x14) */
	uint32_t BAUDR;
	/*!< TX and RX FIFO Control Register */
	/*!< SPI Transmit FIFO Threshold Level Register  (0x18) */
	uint32_t TXFTLR;
	/*!< SPI Receive  FIFO Threshold Level Register  (0x1C) */
	uint32_t RXFTLR;
	/*!< SPI Transmit FIFO Level Register  (0x20) */
	uint32_t TXFLR;
	/*!< SPI Receive  FIFO Level Register  (0x24) */
	uint32_t RXFLR;
	/*!< SPI Status   Register  (0x28) */
	uint32_t SR;
	/*!< Interrupt Enable/Disable/Control Registers */
	/*!< SPI Interrupt Mask Register  (0x2C) */
	uint32_t IMR;
	/*!< SPI Interrupt Status Register  (0x30) */
	uint32_t ISR;
	/*!< SPI Raw Interrupt Status Register (0x34) */
	uint32_t RISR;
	/*!< SPI Transmit FIFO Overflow Interrupt Clear Register  (0x38) */
	uint32_t TXOICR;
	/*!< SPI Receive  FIFO Overflow Interrupt Clear Register  (0x3C) */
	uint32_t RXOICR;
	/*!< SPI Receive FIFO Underflow Interrupt Clear Register  (0x40) */
	uint32_t RXUICR;
	/*!< SPI Multi-Master Interrupt Clear Register  (0x44) */
	uint32_t MSTICR;
	/*!< SPI Interrupt Clear Register  (0x48) */
	uint32_t ICR;
	/*!< DMA Control Register  (0x4C) */
	uint32_t DMACR;
	/*!< DMA Transmit Data Level  (0x50) */
	uint32_t DMATDLR;
	/*!< DMA Receive Data Level  (0x54) */
	uint32_t DMARDLR;
	/*!< SPI Identification Register  (0x58) */
	uint32_t IDR;
	/*!< SPI CoreKit ID Register (Value after Reset : 0x3332322A)  (0x5C) */
	uint32_t SSI_VER_ID;
	/*!< Data Register */
	/*!< SPI DATA Register for both Read and Write  (0x60) */
	uint32_t DATAREG;
	/*!< More SPI DATA Register for both Read and Write  (0x64-0xEC) */
	uint32_t DRS[35];
	/** 0xF0, RxD Sample Delay Register */
	uint32_t RX_SAMPLE_DLY;
	/** 0xF4, SPI Control Register */
	uint32_t SPI_CTRLR0;
} DW_SPI_REG, *DW_SPI_REG_PTR;

/** Designware SPI Message Transfer */
typedef struct dw_spi_transfer {
	uint32_t xfer_len;
	uint32_t tx_idx;
	uint32_t rx_idx;
	uint32_t nbytes;
	DEV_SPI_TRANSFER *tx_xfer;
	DEV_SPI_TRANSFER *rx_xfer;
} DW_SPI_TRANSFER, *DW_SPI_TRANSFER_PTR;

/**
 * \brief	DesignWare SPI control structure definition
 * \details	implement of dev_spi_info::dev_spi_info
 */
typedef struct dw_spi_ctrl {
	DW_SPI_REG *dw_spi_regs;                /*!< spi register */
	/* Variables which should be set during object implementation */
	uint32_t support_modes;                 /*!< supported spi modes */
	uint32_t intno;                         /*!< interrupt no */
	uint32_t dw_apb_bus_freq;               /*!< spi ip apb bus frequency */
	uint32_t rx_sampledly;                  /*!< RxD Sample Delay */
	uint32_t tx_fifo_len;                   /*!< transmit fifo length */
	uint32_t rx_fifo_len;                   /*!< receive fifo length */
	irq_handler dw_spi_int_handler;       /*!< spi interrupt handler */
	/* Variables which always change during spi operation */
	uint32_t int_status;                    /*!< spi interrupt status */
	DW_SPI_TRANSFER dw_xfer;                /*!< designware spi transfer */
} DW_SPI_CTRL, *DW_SPI_CTRL_PTR;

typedef struct {
	/// SPI Device ID
	uint8_t spi_devid;
	/// SPI working speed
	uint32_t spi_speed;
	/// SPI working clock mode
	SPI_CLK_MODE spi_clk;
} DW_SPI_CFG;

void dw_spi_en_xip(DEV_SPI *spi_dev, uint8_t read_cmd, uint8_t cont_byte);
void dw_spi_dis_xip(DEV_SPI *spi_dev);
int32_t dw_spi_open(DEV_SPI *spi_dev, uint32_t mode, uint32_t param);
int32_t dw_spi_close(DEV_SPI *spi_dev);
int32_t dw_spi_control(DEV_SPI *spi_dev, uint32_t ctrl_cmd, void *param);
int32_t dw_spi_write(DEV_SPI *spi_dev, void *w_buf, uint32_t w_len);
int32_t dw_spi_write_read(DEV_SPI *spi_dev, void *w_buf, uint32_t w_len, void *r_buf, uint32_t r_len);
int32_t dw_qspi_write(DEV_SPI *spi_dev, uint8_t *w_buf, uint32_t w_len);
int32_t dw_qspi_write_read(DEV_SPI *spi_dev, uint8_t *w_buf, uint32_t w_len, uint8_t *r_buf, uint32_t r_len);
void dw_spi_isr(DEV_SPI *spi_dev, void *ptr);


#ifdef __cplusplus
}
#endif

#endif /* __DW_SPI_H__ */
